home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / JFC.bin / HTMLDocument.java < prev    next >
Text File  |  1998-06-30  |  37KB  |  1,390 lines

  1. /*
  2.  * @(#)HTMLDocument.java    1.60 98/04/12
  3.  * 
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  */
  20. package com.sun.java.swing.text.html;
  21.  
  22. import java.awt.Color;
  23. import java.awt.Component;
  24. import java.util.Vector;
  25. import java.util.Stack;
  26. import java.util.Enumeration;
  27. import java.net.URL;
  28. import java.net.MalformedURLException;
  29. import java.io.*;
  30. import com.sun.java.swing.*;
  31. import com.sun.java.swing.text.*;
  32. import com.sun.java.swing.Icon;
  33. import com.sun.java.swing.ImageIcon;
  34.  
  35. /**
  36.  * A document that maintains an html element structure.
  37.  * <p>
  38.  * PENDING(prinz) This will be substantially rewritten
  39.  * and made public for the next release.
  40.  * 
  41.  * @author  Timothy Prinzing
  42.  * @author  Sara Swanson
  43.  * @author  Makarand Gokhale
  44.  * @version 1.60 04/12/98
  45.  */
  46. class HTMLDocument extends DefaultStyledDocument {
  47.  
  48.     /**
  49.      * Constructs an html document.
  50.      */
  51.     public HTMLDocument() {
  52.     super();
  53.     }
  54.  
  55.     /**
  56.      * Constructs an html document with the default content
  57.      * storage implementation and a shared set of styles.
  58.      *
  59.      * @param styles the styles
  60.      */
  61.     public HTMLDocument(StyleContext styles) {
  62.         super(new StringContent(BUFFER_SIZE_DEFAULT), styles);
  63.     }
  64.  
  65.     public void setRootElementAttributes(AttributeSet attr) {
  66.     Element section = getDefaultRootElement();
  67.     try {
  68.         writeLock();
  69.             MutableAttributeSet mattr = (MutableAttributeSet) section.getAttributes();
  70.         mattr.addAttributes(attr);
  71.     }
  72.     finally {
  73.         writeUnlock();
  74.     }
  75.     }
  76.  
  77.     public HTMLEditorKit.ParserCallback getReader(int pos) {
  78.     Object desc = getProperty(Document.StreamDescriptionProperty);
  79.     if (desc instanceof URL) { 
  80.         reference = (URL) desc;
  81.     }
  82.     return new HTMLReader(pos);
  83.     }
  84.  
  85.     /**
  86.      * Inserts new elements in bulk.
  87.      *
  88.      * @param offset the starting offset
  89.      * @data the element data
  90.      * @exception BadLocationException for an invalid starting offset
  91.      * @see StyledDocument#insert
  92.      * @exception BadLocationException  if the given position does not 
  93.      *   represent a valid location in the associated document.
  94.      */
  95.     protected void insert(int offset, ElementSpec[] data) throws BadLocationException {
  96.     super.insert(offset, data);
  97.     }
  98.  
  99.     StyleContext getStyleContext() {
  100.     return (StyleContext) getAttributeContext();
  101.     }
  102.  
  103.     /**
  104.      * Return a vector containing any components on the page that were
  105.      * derived from the contents of a FORM tag.
  106.      */
  107.     public void getComponents(Vector compList) {
  108.     AbstractElement section = (AbstractElement)getDefaultRootElement();
  109.     findComponents(section, compList);
  110.     }
  111.  
  112.     /**
  113.      * A recursive function that searches the model for components and
  114.      * determines if they are FORM components.
  115.      */
  116.     private void findComponents(AbstractElement elem, Vector compList) {
  117.         if (elem.isLeaf()) {
  118.         AttributeSet a = elem.getAttributes();
  119.         if (a.getAttribute(Constants.HTMLInputComponent) != null) {
  120.             compList.addElement((Component)a.getAttribute(
  121.             StyleConstants.ComponentAttribute));
  122.         }
  123.         } else {
  124.             int n = elem.getElementCount();
  125.             for (int i = 0; i < n; i++) {
  126.                 AbstractElement e = (AbstractElement) elem.getElement(i);
  127.                 findComponents(e, compList);
  128.             }
  129.         }
  130.     }
  131.  
  132.     /**
  133.      * The location to resolve relative url's against.  By
  134.      * default this will be the documents url if the document
  135.      * was loaded from a url.  If a base tag is found and
  136.      * can be parsed, it will be used as the reference location.
  137.      */
  138.     URL reference;
  139.  
  140.     /**
  141.      * An html reader to load an html document with an html
  142.      * element structure.  This is a set of callbacks from
  143.      * the parser, implemented to create a set of elements
  144.      * tagged with attributes.
  145.      */ 
  146.     class HTMLReader extends HTMLEditorKit.ParserCallback {
  147.  
  148.         public HTMLReader(int offset) {
  149.         StyleContext context = getStyleContext();
  150.         charAttr = context.addStyle(null, null);
  151.         attr = context.addStyle(null, null);
  152.         
  153.         resolver = getStyle(StyleReader.DEFAULT_STYLE_HIERARCHY);
  154.         String hack = " "; // PENDING(prinz) need to fix ElementBuffer
  155.         ElementSpec es = new ElementSpec(
  156.         null, ElementSpec.ContentType, hack.toCharArray(), 0, 1);
  157.         parseBuffer.addElement(es);
  158.         es = new ElementSpec(null, ElementSpec.EndTagType);
  159.         parseBuffer.addElement(es);
  160.     }
  161.  
  162.     /**
  163.      * This is the last method called on the reader.  It allows
  164.      * any pending changes to be flushed into the document.  
  165.      * Since this is currently loading synchronously, the entire
  166.      * set of changes are pushed in at this point.
  167.      */
  168.         public void flush() throws BadLocationException {
  169.         ElementSpec[] spec = new ElementSpec[parseBuffer.size()];
  170.         parseBuffer.copyInto(spec);
  171.         // PENDING(prinz) need to support non-zero offset.
  172.         insert(0, spec);
  173.     }
  174.  
  175.     /**
  176.      * Adds an attribute for the current tag being
  177.      * scanned.
  178.      *
  179.      * @param name the attribute name
  180.      * @param value the attribute value
  181.      */
  182.     public void attributeAction(String name, String value) {
  183.     if (value == null) {
  184.         value = Constants.NULL_ATTRIBUTE;
  185.     }
  186.     attr.addAttribute(name.toLowerCase(), value);
  187.     }
  188.  
  189.     private void setAlignment(MutableAttributeSet a) {
  190.     String align = (String) a.getAttribute(Constants.ALIGN);
  191.     if (align != null) {
  192.         align = align.toLowerCase();
  193.         if (align.equals("left")) {
  194.         StyleConstants.setAlignment(a, StyleConstants.ALIGN_LEFT);
  195.         } else if (align.equals("center")) {
  196.         StyleConstants.setAlignment(a, StyleConstants.ALIGN_CENTER);
  197.         } else if (align.equals("right")) {
  198.         StyleConstants.setAlignment(a, StyleConstants.ALIGN_RIGHT);
  199.         }
  200.     }
  201.     }
  202.  
  203.     public void blockOpenAction(String tag) {
  204.     setAlignment(attr);
  205.     blockOpen(tag, false);
  206.     }
  207.  
  208.     public void blockCloseAction(String tag) {
  209.     blockClose();
  210.     }
  211.  
  212.     public void incrementPCData() {
  213.     if (!dataCountStack.empty()) {
  214.         DataCounter dc = (DataCounter)dataCountStack.pop();
  215.         dc.incCounter();
  216.         dataCountStack.push(dc);
  217.     }
  218.     }
  219.  
  220.     /**
  221.      * Implements the pcdata action to create an ElementSpec
  222.      * record for content with the current character attributes
  223.      * defined.  This is added to the parse buffer
  224.      */
  225.     public void pcdataAction(String data) {
  226.     // Keep track of the pcdata's seen in each nested block
  227.     incrementPCData();
  228.  
  229.     // Translate special characters like ", <, and &034
  230.     String xstr = xlateSpecialChars(data);
  231.     if (xstr != null) {
  232.         data = xstr;
  233.     }
  234.  
  235.     if (inPre) {
  236.         preContent(data);
  237.     } else if (inTitle) {
  238.         titleContent(data);
  239.     } else if (inOption) {
  240.         data = cleanString(data);
  241.         combobox.addItem(data);
  242.     } else if (inBlock > 0) {
  243.         data = cleanString(data);
  244.         if (data.length() >= 1) {
  245.         AttributeSet a = charAttr.copyAttributes();
  246.         ElementSpec es = new ElementSpec(a, ElementSpec.ContentType,
  247.             data.toCharArray(), 0, data.length());
  248.         parseBuffer.addElement(es);
  249.         }
  250.     }
  251.     attr.removeAttributes(attr);
  252.     }
  253.  
  254.     /**
  255.      * cleanEndTag removes any whitespace immediately preceding an
  256.      * end tag.  It also appends an newline character to the text
  257.      * before the end tag so that the insertion caret is positioned
  258.      * properly when editing.
  259.      */
  260.     protected void cleanEndTag(boolean endParagraphSeen) {
  261.     // Fetch the last character data added to the parseBuffer
  262.     ElementSpec lastes = (ElementSpec) parseBuffer.lastElement();
  263.     if (lastes == null)
  264.         return;
  265.     char [] lastchars = lastes.getArray();
  266.     if (lastchars == null)
  267.         return;
  268.     String clean = new String (lastchars);
  269.     if (clean.length() == 0)
  270.         return;
  271.  
  272.     // Eat last whitespace - there's exactly one trailing whitespace
  273.     // because the string was trimmed in cleanString & one space was
  274.     // appended.
  275.     if (isWhiteSpace(clean.charAt(clean.length() - 1))) {
  276.         clean = clean.substring(0, clean.length() - 1);
  277.     }
  278.  
  279.     // For proper cursor positioning during editing,there must be a
  280.     // newline at the end of each paragraph.
  281.     if (endParagraphSeen) {
  282.         clean = clean + "\n";
  283.     }
  284.  
  285.     // Replace the last character data with the modified string
  286.     // in the parseBuffer
  287.     ElementSpec es = new ElementSpec(lastes.getAttributes(),
  288.         ElementSpec.ContentType, clean.toCharArray(),
  289.         0, clean.length());
  290.     parseBuffer.removeElementAt(parseBuffer.size() - 1);
  291.     parseBuffer.addElement(es);
  292.     }
  293.  
  294.     /**
  295.      * isWhiteSpace returns true if a character is whitespace and
  296.      * otherwise returns false.
  297.      */
  298.     protected boolean isWhiteSpace(char c) {
  299.     if ((c == ' ')
  300.      || (c == 10)
  301.      || (c == 13)
  302.      || (c == '\t')) { 
  303.         return true;
  304.     } else {
  305.         return false;
  306.     }
  307.     }
  308.  
  309.     /**
  310.      * cleanString replaces any sequence of blanks, tabs, & newlines 
  311.      *     with a single blank where a newline equals CR LF, CR only,
  312.      *     or LF only.
  313.      * A newline immediately following a start tag is trimmed.
  314.      */
  315.     protected String cleanString(String s) {
  316.     if (s.length() < 1)
  317.         return s;
  318.  
  319.     // Remove all preceding & trailing whitespace & replace with a
  320.     // single space.  If there is no whitespace to begin with, don't
  321.     // add any.
  322.     String endSpace = "";
  323.     String begSpace = "";
  324.     if ((s.length() > 1) 
  325.         && isWhiteSpace(s.charAt(s.length()-1)))
  326.         endSpace = new String (" ");
  327.     if (isWhiteSpace(s.charAt(0)))
  328.         begSpace = new String (" ");
  329.     String clean = begSpace + s.trim() + endSpace; 
  330.  
  331.     // Remove all preceding white space if the pcdata immediately
  332.     // follows an open tag.
  333.     if (openTagSeen && begSpace.equals(" ")) {
  334.         clean = clean.substring(1, clean.length());
  335.     }
  336.     openTagSeen = false;
  337.  
  338.     // Search the entire string for whitespace & replace any sequence
  339.     // of blanks, tabs, & newlines with a single space.
  340.         int index = 0;
  341.         while (index < clean.length()) {
  342.         int endindex = index;
  343.         // Eat whitespace
  344.         if (isWhiteSpace(clean.charAt(endindex))) {
  345.         while ((endindex < clean.length())
  346.             && (isWhiteSpace(clean.charAt(endindex)))) {
  347.             endindex++;
  348.         }
  349.         clean = clean.substring(0, index) + " "
  350.             + clean.substring(endindex, clean.length());
  351.         index = endindex;
  352.         } else {
  353.             index++;
  354.         }
  355.     }
  356.  
  357.     return clean;
  358.     }
  359.  
  360.         
  361.     public void fontOpenAction() {
  362.     openTagSeen = true;
  363.     pushCharacterStyle();
  364.     Color fg = getColor(attr);
  365.     if (fg != null) {
  366.         StyleConstants.setForeground(charAttr, fg);
  367.     }
  368.     String face = (String) attr.getAttribute(Constants.FACE);
  369.     if (face != null) {
  370.         StyleConstants.setFontFamily(charAttr, face);
  371.     }
  372.     String size = (String) attr.getAttribute(Constants.SIZE);
  373.     StyleSheet ss = StyleReader.getStyleSheet();
  374.     if (size != null) {
  375.         StyleConstants.setFontSize(charAttr, ss.getPtSize(size));
  376.     }
  377.     }
  378.  
  379.     public void fontCloseAction() {
  380.     popCharacterStyle();
  381.     }
  382.  
  383.     public void htmlOpenAction() {
  384.     ;
  385.     }
  386.  
  387.     public void htmlCloseAction() {
  388.     ;
  389.     }
  390.  
  391.     public void headOpenAction() {
  392.     ;
  393.     }
  394.  
  395.     public void headCloseAction() {
  396.     ;
  397.     }
  398.  
  399.     public void bodyOpenAction() {
  400.     setRootElementAttributes(attr);
  401.     }
  402.  
  403.     public void bodyCloseAction() {
  404.     }
  405.  
  406.     public void whitespaceAction(String data) {
  407.     ;
  408.     addContent(data);
  409.     }
  410.  
  411.     public void titleOpenAction() {
  412.     ;
  413.     inTitle = true;
  414.     }
  415.  
  416.     public void titleCloseAction() {
  417.     ;
  418.     inTitle = false;
  419.     }
  420.  
  421.     public void preOpenAction() {
  422.     inPre = true;
  423.     blockOpen(Constants.PRE, true);
  424.     blockOpen(Constants.PRELINE, true);
  425.     }
  426.  
  427.     public void preCloseAction() {
  428.     inPre = false;
  429.     blockClose();
  430.     blockClose();
  431.     }
  432.  
  433.     /**
  434.      * Set the title as a property on the doc.
  435.      */
  436.     void titleContent(String s) {
  437.     putProperty(Document.TitleProperty, s);
  438.     }
  439.  
  440.     void preContent(String s) {
  441.     int last = 0;
  442.     for (int index = s.indexOf('\n'); index >= 0; index = s.indexOf('\n', last)) {
  443.         String chunk = s.substring(last, index);
  444.         addContent(chunk);
  445.         blockClose();
  446.         blockOpen(Constants.PRELINE, true);
  447.         last = index + 1;
  448.     }
  449.     if (last < s.length()) {
  450.         addContent(s.substring(last, s.length()));
  451.     }
  452.     }
  453.  
  454.     public void ttOpenAction() {
  455.     pushCharacterStyle();
  456.     attr.addAttribute(Constants.TT, "true");
  457.     AttributeSet look = getStyleSheetStyle(Constants.TT);
  458.     if (look != null) {
  459.         charAttr.addAttributes(look);
  460.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  461.     }
  462.     else 
  463.         StyleConstants.setFontFamily(charAttr, "Monospaced");
  464.        
  465.     charAttr.addAttributes(attr);
  466.     }
  467.  
  468.     public void ttCloseAction() {
  469.     popCharacterStyle();
  470.     }
  471.  
  472.     public void dfnOpenAction() {
  473.     pushCharacterStyle();
  474.     AttributeSet look = getStyleSheetStyle(Constants.DFN);
  475.     if (look != null) {
  476.         charAttr.addAttributes(look);
  477.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  478.     }
  479.     else 
  480.         StyleConstants.setItalic(charAttr, true);
  481.        
  482.     charAttr.addAttributes(attr);
  483.     }
  484.  
  485.     public void dfnCloseAction() {
  486.     popCharacterStyle();
  487.     }
  488.  
  489.     public void citeOpenAction() {
  490.     pushCharacterStyle();
  491.     AttributeSet look = getStyleSheetStyle(Constants.CITE);
  492.     if (look != null) {
  493.         charAttr.addAttributes(look);
  494.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  495.     }
  496.     else 
  497.         StyleConstants.setItalic(charAttr, true);
  498.        
  499.     charAttr.addAttributes(attr);
  500.     }
  501.  
  502.     public void citeCloseAction() {
  503.     popCharacterStyle();
  504.     }
  505.  
  506.     public void bigOpenAction() {
  507.     pushCharacterStyle();
  508.     AttributeSet look = getStyleSheetStyle(Constants.BIG);
  509.     if (look != null) {
  510.         charAttr.addAttributes(look);
  511.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  512.     }
  513.     else {
  514.         String fontval = StyleXlater.convertFontSizeString("x-large");
  515.         StyleSheet ss = StyleReader.getStyleSheet();
  516.         int size = ss.getPtSize(fontval);
  517.         StyleConstants.setFontSize(charAttr, size);
  518.     }
  519.        
  520.     }
  521.  
  522.     public void bigCloseAction() {
  523.     popCharacterStyle();
  524.     }
  525.  
  526.     public void smallOpenAction() {
  527.     pushCharacterStyle();
  528.     AttributeSet look = getStyleSheetStyle(Constants.SMALL);
  529.     if (look != null) {
  530.         charAttr.addAttributes(look);
  531.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  532.     }
  533.     else {
  534.         String fontval = StyleXlater.convertFontSizeString("x-small");
  535.         StyleSheet ss = StyleReader.getStyleSheet();
  536.         int size = ss.getPtSize(fontval);
  537.         StyleConstants.setFontSize(charAttr, size);
  538.     }
  539.        
  540.     }
  541.  
  542.     public void smallCloseAction() {
  543.     popCharacterStyle();
  544.     }
  545.  
  546.     public void sampOpenAction() {
  547.     pushCharacterStyle();
  548.     AttributeSet look = getStyleSheetStyle(Constants.SAMP);
  549.     if (look != null) {
  550.         charAttr.addAttributes(look);
  551.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  552.     }
  553.     else {
  554.         String fontval = StyleXlater.convertFontSizeString("small");
  555.         StyleSheet ss = StyleReader.getStyleSheet();
  556.         int size = ss.getPtSize(fontval);
  557.         StyleConstants.setFontSize(charAttr, size);
  558.         StyleConstants.setFontFamily(charAttr, "Monospaced");
  559.     }
  560.        
  561.     }
  562.  
  563.     public void sampCloseAction() {
  564.     popCharacterStyle();
  565.     }
  566.  
  567.     public void codeOpenAction() {
  568.     pushCharacterStyle();
  569.     AttributeSet look = getStyleSheetStyle(Constants.CODE);
  570.     if (look != null) {
  571.         charAttr.addAttributes(look);
  572.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  573.     }
  574.     else {
  575.         String fontval = StyleXlater.convertFontSizeString("small");
  576.         StyleSheet ss = StyleReader.getStyleSheet();
  577.         int size = ss.getPtSize(fontval);
  578.         StyleConstants.setFontSize(charAttr, size);
  579.         StyleConstants.setFontFamily(charAttr, "Monospaced");
  580.     }
  581.        
  582.     }
  583.  
  584.     public void codeCloseAction() {
  585.     popCharacterStyle();
  586.     }
  587.  
  588.     public void strikeOpenAction() {
  589.     pushCharacterStyle();
  590.     AttributeSet look = getStyleSheetStyle(Constants.STRIKE);
  591.     if (look != null) {
  592.         charAttr.addAttributes(look);
  593.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  594.     }
  595.     else {
  596.        ; // Add code here to do strikethrough when implemented in text.
  597.     }
  598.        
  599.     }
  600.  
  601.     public void strikeCloseAction() {
  602.     popCharacterStyle();
  603.     }
  604.  
  605.     public void blockquoteOpenAction() {
  606.     blockOpen(Constants.BLOCKQUOTE, false);
  607.     }
  608.  
  609.     public void blockquoteCloseAction() {
  610.     blockClose();
  611.     }
  612.  
  613.     public void emOpenAction() {
  614.     pushCharacterStyle();
  615.     AttributeSet look = getStyleSheetStyle(Constants.EM);
  616.     if (look != null) {
  617.         charAttr.addAttributes(look);
  618.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  619.     }
  620.     else
  621.       StyleConstants.setItalic(charAttr, true);
  622.       
  623.     charAttr.addAttributes(attr);
  624.     }
  625.  
  626.     public void emCloseAction() {
  627.     popCharacterStyle();
  628.     }
  629.  
  630.     public void addressOpenAction() {
  631.     pushCharacterStyle();
  632.     AttributeSet look = getStyleSheetStyle(Constants.ADDRESS);
  633.     if (look != null) {
  634.         charAttr.addAttributes(look);
  635.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  636.     }
  637.     else
  638.       StyleConstants.setItalic(charAttr, true);
  639.       
  640.     charAttr.addAttributes(attr);
  641.     }
  642.  
  643.     public void addressCloseAction() {
  644.     popCharacterStyle();
  645.     }
  646.  
  647.     public void strongOpenAction() {
  648.     pushCharacterStyle();
  649.     AttributeSet look = getStyleSheetStyle(Constants.STRONG);
  650.     if (look != null) {
  651.         charAttr.addAttributes(look);
  652.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  653.     }
  654.     else
  655.         StyleConstants.setBold(charAttr, true);
  656.  
  657.     charAttr.addAttributes(attr);
  658.     }
  659.  
  660.     public void strongCloseAction() {
  661.     popCharacterStyle();
  662.     }
  663.  
  664.     public void varOpenAction() {
  665.     pushCharacterStyle();
  666.     // Use "var" instead of HTMLDefs.VAR because that is defined as "_var"
  667.     AttributeSet look = getStyleSheetStyle("var");
  668.     if (look != null) {
  669.         charAttr.addAttributes(look);
  670.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  671.     }
  672.     else {
  673.       StyleConstants.setBold(charAttr, true);
  674.       StyleConstants.setItalic(charAttr, true);
  675.     }
  676.     charAttr.addAttributes(attr);
  677.     }
  678.  
  679.     public void varCloseAction() {
  680.     popCharacterStyle();
  681.     }
  682.  
  683.     public void basefontAction() {
  684.  
  685. /** This is wrong.
  686.   It sets all Paragraphs to be that basefont size
  687.   even if the basefont tag was in the middle of the doc
  688.  
  689.   If we set the size on the charAttr, then it only
  690.   takes effect for those within this character style run.
  691.  
  692.     String size = (String) attr.getAttribute(SIZE);
  693.     if (size != null) {
  694.         StyleSheet ss = StyleReader.getStyleSheet();
  695.         ss.setBaseFontSize(size);
  696.         //Style defStyle = getStyle(StyleContext.DEFAULT_STYLE);
  697.         Style style = getStyleSheetStyle(P);
  698.         // This currently only changes text in a P block.
  699.         StyleConstants.setFontSize(style, ss.getPtSize(size));
  700.     }
  701. */
  702.  
  703.     //
  704.     // Save this attribute on the element for writing.
  705.     //
  706.     attr.addAttribute(Constants.HTMLTagAttribute, Constants.BASEFONT);
  707.     addSpecialElement(attr);
  708.  
  709.     }
  710.  
  711.     public void brAction() {
  712. /*
  713.     blockOpen(BR, false);
  714.     AttributeSet a = charAttr.copyAttributes();
  715.     ElementSpec es = new ElementSpec(a, ElementSpec.ContentType,
  716.         null, 0, 0);
  717.     parseBuffer.addElement(es);
  718.     blockClose();
  719. */
  720.     ;
  721.     }
  722.  
  723.     public void aOpenAction() {
  724.     pushCharacterStyle();
  725.     AttributeSet look = getStyleSheetStyle(Constants.A);
  726.     if (look != null) {
  727.         charAttr.addAttributes(look);
  728.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  729.     }
  730.     charAttr.addAttributes(attr);
  731.     }
  732.  
  733.     private void checkPCData() {
  734.     // If no pcdata was found, add an empty content anyway
  735.     if (!dataCountStack.empty()) {
  736.         DataCounter dc = (DataCounter)dataCountStack.peek();
  737.         if (dc.noPCData()) {
  738.         AttributeSet a = charAttr.copyAttributes();
  739.         String empty = new String("");
  740.         ElementSpec es = new ElementSpec(a, ElementSpec.ContentType,
  741.             empty.toCharArray(), 0, empty.length());
  742.         parseBuffer.addElement(es);
  743.         }    
  744.     }
  745.     }
  746.  
  747.     public void aCloseAction() {
  748.     checkPCData();
  749.     popCharacterStyle();
  750.     }
  751.  
  752.     public void hrAction() {
  753.     // Get the margins off the body & set them on the hr
  754.     /*
  755.     Style candidate = (Style)getStyleSheetStyle(BODY);
  756.     if (candidate != null) {
  757.         float margin_left = StyleConstants.getLeftIndent(candidate);
  758.         float margin_right = StyleConstants.getRightIndent(candidate);
  759.         StyleConstants.setLeftIndent(attr, margin_left);
  760.         StyleConstants.setRightIndent(attr, margin_right);
  761.     }
  762.     */
  763.  
  764.     setAlignment(attr);
  765.     attr.addAttribute(AbstractDocument.ElementNameAttribute, Constants.HR);
  766.     addSpecialElement(attr);
  767.     }
  768.  
  769.     public void imgAction() {
  770.     attr.addAttribute(AbstractDocument.ElementNameAttribute, Constants.IMG);
  771.     attr.addAttributes(charAttr);    // so ImageView will know char color
  772.     addSpecialElement(attr);
  773.     }
  774.  
  775.     public void iOpenAction() {
  776.     pushCharacterStyle();
  777.     AttributeSet look = getStyleSheetStyle(Constants.I);
  778.     if (look != null) {
  779.         charAttr.addAttributes(look);
  780.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  781.     }
  782.     else
  783.       StyleConstants.setItalic(charAttr, true);
  784.       
  785.     charAttr.addAttributes(attr);
  786.     }
  787.     public void iCloseAction() {
  788.     popCharacterStyle();
  789.     }
  790.  
  791.     public void bOpenAction() {
  792.     pushCharacterStyle();
  793.     AttributeSet look = getStyleSheetStyle(Constants.B);
  794.     if (look != null) {
  795.         charAttr.addAttributes(look);
  796.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  797.     }
  798.     else
  799.       StyleConstants.setBold(charAttr, true);
  800.  
  801.     charAttr.addAttributes(attr);
  802.     }
  803.     public void bCloseAction() {
  804.     popCharacterStyle();
  805.     }
  806.  
  807.     public void uOpenAction() {
  808.     pushCharacterStyle();
  809.     AttributeSet look = getStyleSheetStyle(Constants.U);
  810.     if (look != null) {
  811.         charAttr.addAttributes(look);
  812.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  813.     }
  814.     else
  815.         StyleConstants.setUnderline(charAttr, true);
  816.     }
  817.     public void uCloseAction() {
  818.     popCharacterStyle();
  819.     }
  820.  
  821.     public void kbdOpenAction() {
  822.     pushCharacterStyle();
  823.     AttributeSet look = getStyleSheetStyle(Constants.KBD);
  824.     if (look != null) {
  825.         charAttr.addAttributes(look);
  826.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  827.     }
  828.     else {
  829.         StyleConstants.setFontFamily(charAttr, "Monospaced");
  830.         String fontval = StyleXlater.convertFontSizeString("small");
  831.         StyleSheet ss = StyleReader.getStyleSheet();
  832.         int size = ss.getPtSize(fontval);
  833.         StyleConstants.setFontSize(charAttr, size);
  834.     }
  835.  
  836.     charAttr.addAttributes(attr);
  837.     }
  838.  
  839.     public void kbdCloseAction() {
  840.     popCharacterStyle();
  841.     }
  842.  
  843.     public void baseAction() {
  844.     String href = (String) attr.getAttribute(Constants.HREF);
  845.     if (href != null) {
  846.         putProperty(Constants.BaseHrefProperty, href);
  847.         try {
  848.         reference = new URL(href);
  849.         } catch (MalformedURLException ex) {
  850.         }
  851.     }
  852.     }
  853.  
  854.     public void subOpenAction() {
  855.     openTagSeen = true;
  856.     pushCharacterStyle();
  857.     AttributeSet look = getStyleSheetStyle(Constants.SUB);
  858.     if (look != null) {
  859.         charAttr.addAttributes(look);
  860.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  861.     }
  862.     //else
  863.         // set subscripting
  864.         //StyleConstants.set*
  865.     charAttr.addAttributes(attr);
  866.     }
  867.     public void subCloseAction() {
  868.     cleanEndTag(false);
  869.     popCharacterStyle();
  870.     }
  871.  
  872.     public void supOpenAction() {
  873.     openTagSeen = true;
  874.     attr.addAttribute(Constants.SUP, "true");
  875.     pushCharacterStyle();
  876.     AttributeSet look = getStyleSheetStyle(Constants.SUP);
  877.     if (look != null) {
  878.         charAttr.addAttributes(look);
  879.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  880.     }
  881.     //else
  882.         // set superscripting
  883.         //StyleConstants.set*(charAttr, true);
  884.  
  885.     charAttr.addAttributes(attr);
  886.     }
  887.     public void supCloseAction() {
  888.     cleanEndTag(false);
  889.     popCharacterStyle();
  890.     }
  891.  
  892.  
  893.     // --- list actions ---------------------------
  894.  
  895.     public void liOpenAction() {
  896.     blockOpen(Constants.LI, true);
  897.     }
  898.     public void liCloseAction() {
  899.     blockClose();
  900.     }
  901.     public void ulOpenAction() {
  902.     blockOpen(Constants.UL, true);
  903.     }
  904.     public void ulCloseAction() {
  905.     blockClose();
  906.     }
  907.     public void olOpenAction() {
  908.     blockOpen(Constants.OL, true);
  909.     }
  910.     public void olCloseAction() {
  911.     blockClose();
  912.     }
  913.     public void dlOpenAction() {
  914.     blockOpen(Constants.DL, true);
  915.     }
  916.     public void dlCloseAction() {
  917.     blockClose();
  918.     }
  919.     public void ddOpenAction() {
  920.     blockOpen(Constants.DD, true);
  921.     }
  922.     public void ddCloseAction() {
  923.     blockClose();
  924.     }
  925.     public void dtOpenAction() {
  926.     blockOpen(Constants.DT, true);
  927.     }
  928.     public void dtCloseAction() {
  929.     blockClose();
  930.     }
  931.     public void dirOpenAction() {
  932.     blockOpen(Constants.DIR, true);
  933.     }
  934.     public void dirCloseAction() {
  935.     blockClose();
  936.     }
  937.     public void menuOpenAction() {
  938.     blockOpen(Constants.MENU, true);
  939.     }
  940.     public void menuCloseAction() {
  941.     blockClose();
  942.     }
  943.  
  944.     // --- form actions ---------------------------
  945.  
  946.     public void formOpenAction(){
  947. //    blockOpen(FORM, true);
  948.     }
  949.  
  950.     public void formCloseAction(){
  951. //    blockClose();
  952.     }
  953.  
  954.     public void inputAction(){
  955.     String type = (String) attr.getAttribute(Constants.TYPE);
  956.     if (type == null)
  957.         type = new String("text");
  958.  
  959.     if (type.equalsIgnoreCase("hidden")) {
  960.         addSpecialElement(attr);
  961.         return;
  962.     }
  963.  
  964.     Component c;
  965.     if (type.equalsIgnoreCase("submit")
  966.         || type.equalsIgnoreCase("reset")) {
  967.         String value = (String) attr.getAttribute(Constants.VALUE);
  968.         c = (Component) new JButton(value);
  969.     } else if (type.equalsIgnoreCase("image")) {
  970.         String src = (String) attr.getAttribute(Constants.SRC);
  971.         c = (Component) new JButton(src);
  972.     } else if (type.equalsIgnoreCase("checkbox")) {
  973.         c = (Component) new JCheckBox();
  974.     } else if (type.equalsIgnoreCase("radio")) {
  975.         String value = (String) attr.getAttribute(Constants.VALUE);
  976.  
  977.         c = (Component) new JRadioButton(value);
  978.     } else if (type.equalsIgnoreCase("text")
  979.         || type.equalsIgnoreCase("password")) {
  980.         int size;
  981.         String sizestr = (String) attr.getAttribute(Constants.SIZE);
  982.         if (sizestr != null) {
  983.                 try {
  984.             size = Integer.valueOf(sizestr).intValue();
  985.                 } catch (NumberFormatException e) {
  986.             size = 40;
  987.                 }
  988.         } else {
  989.         size = 40;
  990.         }
  991.  
  992.         String value = (String) attr.getAttribute(Constants.VALUE);
  993.  
  994.         c = (Component) new JTextField(value, size);
  995.     } else {
  996.         c = (Component) new JButton();
  997.     }
  998.     attr.addAttribute(Constants.HTMLInputComponent, Constants.HTMLInputComponent);
  999.     StyleConstants.setComponent(attr, c);
  1000.     addSpecialElement(attr);
  1001.     }
  1002.  
  1003.     public void selectOpenAction(){
  1004.     Component c;
  1005.  
  1006.     int rows;
  1007.     String rowsstr = (String) attr.getAttribute(Constants.ROWS);
  1008.     if (rowsstr != null) {
  1009.             try {
  1010.             rows = Integer.valueOf(rowsstr).intValue();
  1011.             } catch (NumberFormatException e) {
  1012.             rows = 10;
  1013.             }
  1014.     } else {
  1015.         rows = 10;
  1016.     }
  1017.  
  1018.     int cols;
  1019.     String colsstr = (String) attr.getAttribute(Constants.COLS);
  1020.     if (colsstr != null) {
  1021.             try {
  1022.             cols = Integer.valueOf(colsstr).intValue();
  1023.             } catch (NumberFormatException e) {
  1024.             cols = 40;
  1025.             }
  1026.     } else {
  1027.         cols = 40;
  1028.     }
  1029.  
  1030.     String value = (String) attr.getAttribute(Constants.VALUE);
  1031.  
  1032.         combobox = new JComboBox();
  1033.         combobox.setEditable(false);
  1034.  
  1035.     c = (Component) combobox; 
  1036.     attr.addAttribute(Constants.HTMLInputComponent, Constants.HTMLInputComponent);
  1037.     StyleConstants.setComponent(attr, c);
  1038.     addSpecialElement(attr);
  1039.     }
  1040.  
  1041.     public void selectCloseAction(){
  1042.     }
  1043.  
  1044.     public void optionOpenAction(){
  1045.     inOption = true;
  1046.     }
  1047.  
  1048.     public void optionCloseAction(){
  1049.     inOption = false;
  1050.     }
  1051.  
  1052.     public void textareaOpenAction(){
  1053.     Component c;
  1054.  
  1055.     int rows;
  1056.     String rowsstr = (String) attr.getAttribute(Constants.ROWS);
  1057.     if (rowsstr != null) {
  1058.             try {
  1059.             rows = Integer.valueOf(rowsstr).intValue();
  1060.             } catch (NumberFormatException e) {
  1061.             rows = 10;
  1062.             }
  1063.     } else {
  1064.         rows = 10;
  1065.     }
  1066.  
  1067.     int cols;
  1068.     String colsstr = (String) attr.getAttribute(Constants.COLS);
  1069.     if (colsstr != null) {
  1070.             try {
  1071.             cols = Integer.valueOf(colsstr).intValue();
  1072.             } catch (NumberFormatException e) {
  1073.             cols = 40;
  1074.             }
  1075.     } else {
  1076.         cols = 40;
  1077.     }
  1078.  
  1079.     String value = (String) attr.getAttribute(Constants.VALUE);
  1080.  
  1081.         JTextArea ta = new JTextArea(value, rows, cols);
  1082.         ta.setEditable(true);
  1083.  
  1084.         JScrollPane scroller = new JScrollPane(
  1085.         JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
  1086.         JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
  1087.         scroller.getViewport().add(ta);
  1088.  
  1089.     c = (Component) scroller; 
  1090.     attr.addAttribute(Constants.HTMLInputComponent, Constants.HTMLInputComponent);
  1091.     StyleConstants.setComponent(attr, c);
  1092.     addSpecialElement(attr);
  1093.     }
  1094.  
  1095.     public void textareaCloseAction(){
  1096.     }
  1097.  
  1098.     // --- table actions -------------------
  1099. /*
  1100.     public void tableOpenAction() {
  1101.     blockOpen(Constants.TABLE, true);
  1102.     }
  1103.     public void tableCloseAction() {
  1104.     blockClose();
  1105.     }
  1106.  
  1107.     public void trOpenAction() {
  1108.     blockOpen(Constants.TR, true);
  1109.     }
  1110.     public void trCloseAction() {
  1111.     blockClose();
  1112.     }
  1113.  
  1114.     public void thOpenAction() {
  1115.     blockOpen(Constants.TH, true);
  1116.     }
  1117.     public void thCloseAction() {
  1118.     blockClose();
  1119.     }
  1120.  
  1121.     public void tdOpenAction() {
  1122.     blockOpen(Constants.TD, true);
  1123.     }
  1124.     public void tdCloseAction() {
  1125.     blockClose();
  1126.     }
  1127.  
  1128.     public void captionOpenAction() {
  1129.     blockOpen(Constants.CAPTION, true);
  1130.     }
  1131.     public void captionCloseAction() {
  1132.     blockClose();
  1133.     }
  1134. */
  1135.     // --- utility methods used by the reader ------------------
  1136.  
  1137.     /**
  1138.      * Fetches the CHILD_STYLE from a named style previously added.
  1139.      *
  1140.      * @param nm  the name of the style
  1141.      * @return the style
  1142.      */
  1143.         protected Style getStyleSheetStyle(String nm) {
  1144.         Style shStyle = getStyle("SH" + nm);
  1145.         return (Style)shStyle.getAttribute(StyleReader.CHILD_STYLE);
  1146.     }
  1147.  
  1148.     /**
  1149.      * Try to turn an html color spec into a Color object.
  1150.      */
  1151.     Color getColor(AttributeSet a) {
  1152.     String name = (String) attr.getAttribute(Constants.COLOR);
  1153.     if (name != null) {
  1154.         Color c = Utilities.stringToColor(name);
  1155.         return c;
  1156.     }
  1157.     return null;
  1158.     }
  1159.  
  1160.     /**
  1161.      * Push the current character style on a stack in preparation
  1162.      * for forming a new nested character style.
  1163.      */
  1164.     void pushCharacterStyle() {
  1165.     charAttrStack.push(charAttr.copyAttributes());
  1166.     }
  1167.  
  1168.     /**
  1169.      * Pop a previously pushed character style off the stack
  1170.      * to return to a previous style.
  1171.      */
  1172.     void popCharacterStyle() {
  1173.     charAttr = (MutableAttributeSet) charAttrStack.peek();
  1174.     charAttrStack.pop();
  1175.     }
  1176.  
  1177.     /**
  1178.      * Push the current logical style on the style stack and
  1179.      * set the current logical style to new named style (as
  1180.      * it resolves from the old style.
  1181.      */
  1182.     void pushStyle(String name) {
  1183.     styleStack.push(resolver);
  1184.     
  1185.     // FIXME - should create a local def if it doesn't
  1186.     // exist, so that styles can later be dynamically
  1187.     // updated and the element will be pointing to the
  1188.     // correct style if one is added!!
  1189.     String str = "SH" + name;
  1190.     Style candidate = (Style) resolver.getAttribute(str);
  1191.     if ((candidate == null) && name.equalsIgnoreCase(Constants.IMPLIEDP)) {
  1192.         str = new String("SHp");
  1193.         candidate = (Style) resolver.getAttribute(str);
  1194.     }
  1195.  
  1196.     if (candidate != null) {
  1197.         resolver = candidate;
  1198.     }
  1199.     }
  1200.  
  1201.     /**
  1202.      * Restores a previously pushed style back as the current
  1203.      * style.
  1204.      */
  1205.     void popStyle() {
  1206.     resolver = (Style) styleStack.peek();
  1207.     styleStack.pop();
  1208.     }
  1209.  
  1210.     /**
  1211.      * Add a specification to create a new branch element,
  1212.      * optionally with the given tag name.
  1213.      */
  1214.     void blockOpen(String tag, boolean setName) {
  1215.     // Increment the parent data count to include this block
  1216.     incrementPCData();
  1217.     // Keep track of the pcdata's seen in each nested block
  1218.     dataCountStack.push(new DataCounter());
  1219.  
  1220.     openTagSeen = true;
  1221.     inBlock++;
  1222.     pushStyle(tag);
  1223.     //Style s = getStyle(tag);
  1224.     if (resolver != null) {
  1225.         // resolve to the tag-named style if it exists
  1226.         Style tmpResolver 
  1227.         = (Style) resolver.getAttribute(StyleReader.CHILD_STYLE);
  1228.         if (tmpResolver != null) {
  1229.             attr.addAttribute(StyleConstants.ResolveAttribute, tmpResolver);
  1230.         }
  1231.     }
  1232.     if (setName) {
  1233.         attr.addAttribute(AbstractDocument.ElementNameAttribute, tag);
  1234.     }
  1235.     if (tag.equalsIgnoreCase(Constants.IMPLIEDP)) {
  1236.         attr.addAttribute(Constants.IMPLIEDP, Constants.IMPLIEDP);
  1237.     }
  1238.     ElementSpec es = new ElementSpec(
  1239.         attr.copyAttributes(), ElementSpec.StartTagType);
  1240.     parseBuffer.addElement(es);
  1241.     attr.removeAttributes(attr);
  1242.     }
  1243.  
  1244.     /**
  1245.      * Close out an element.
  1246.      */
  1247.     void blockClose() {
  1248.     // Keep track of the pcdata's seen in each nested block
  1249.     checkPCData();
  1250.     dataCountStack.pop();
  1251.  
  1252.     cleanEndTag(true);
  1253.     inBlock --;
  1254.     popStyle();
  1255.  
  1256.     // an open/close with no content will be removed, so we
  1257.     // add a space of content to keep the element being formed.
  1258.     ElementSpec prev = (ElementSpec) parseBuffer.lastElement();
  1259.     if (prev != null && prev.getType() == ElementSpec.StartTagType) {
  1260.         addContent(" ");
  1261.     }
  1262.  
  1263.     ElementSpec es = new ElementSpec(
  1264.         null, ElementSpec.EndTagType);
  1265.     parseBuffer.addElement(es);
  1266.     }
  1267.  
  1268.     /**
  1269.      * Add some text with the current character attributes
  1270.      */
  1271.     void addContent(String data) {
  1272.     AttributeSet a = charAttr.copyAttributes();
  1273.     ElementSpec es = new ElementSpec(
  1274.         a, ElementSpec.ContentType, data.toCharArray(), 0, data.length());
  1275.     parseBuffer.addElement(es);
  1276.     }
  1277.  
  1278.     /**
  1279.      * Add content that is basically specified entirely
  1280.      * in the attribute set.
  1281.      */
  1282.     void addSpecialElement(AttributeSet a) {
  1283.     char[] one = new char[1];
  1284.     one[0] = ' ';
  1285.     a = a.copyAttributes();
  1286.     ElementSpec es = new ElementSpec(
  1287.         a.copyAttributes(), ElementSpec.ContentType, one, 0, 1);
  1288.     parseBuffer.addElement(es);
  1289.  
  1290.     attr.removeAttributes(attr);
  1291.     }
  1292.  
  1293.     /**
  1294.      * Replace the substring in str indicated by the start and end
  1295.      * indices with the character.
  1296.      */
  1297.     private String replaceSpecialChar(String str, int startindex,
  1298.     int endindex, char ch) {
  1299.  
  1300.     String newstr = null;
  1301.     newstr = str.substring(0, startindex) + ch
  1302.             + str.substring(endindex+1, str.length());
  1303.     return(newstr);
  1304.     }
  1305.  
  1306.     /**
  1307.      * Translate embedded character entities into their respective
  1308.      * characters.
  1309.      */
  1310.     protected String xlateSpecialChars(String str) {
  1311.         String result = null;
  1312.         int index = 0;
  1313.  
  1314.         // Look for the '&' character which designates special html chars.
  1315.         index = str.indexOf('&');
  1316.         while ((index < str.length()) && (index >= 0)) {
  1317.             // The special character description ends with ';' so find the
  1318.             // beginning and ending indexes of the special character.
  1319.             int jindex = 0;
  1320.             jindex = str.indexOf(';', index);
  1321.             if (jindex < 0) {
  1322.                 return(null);
  1323.             }
  1324.  
  1325.             // If a '#' character follows '&' then the special character is
  1326.             // being represented by an ascii numeric code.  Replace the
  1327.             // code with the special character itself and return the string.
  1328.             if (str.charAt(index+1) == '#') {
  1329.                 String sstr = str.substring(index+2, jindex); 
  1330.                 int num = Integer.valueOf(sstr).intValue();
  1331.                 str = replaceSpecialChar(str, index, jindex, (char)num);
  1332.             }
  1333.             // Otherwise, look up the character name (e.g. ") in the
  1334.             // SpecialCharTable.  Replace the code with the special
  1335.             // character itself and return the string.
  1336.             else {
  1337.                 String sstr = str.substring(index+1, jindex); 
  1338.                 char lookup = specTable.getSymbol(sstr);
  1339.                 if (lookup != '\0') {
  1340.                     str = replaceSpecialChar(str, index, jindex, lookup);
  1341.                 }
  1342.             }
  1343.             
  1344.             index = str.indexOf('&', index + 1);
  1345.         }
  1346.  
  1347.         return str;
  1348.     }
  1349.  
  1350.     boolean openTagSeen = false;
  1351.     boolean inPre = false;
  1352.     boolean inTitle = false;
  1353.     boolean inOption = false;
  1354.     Stack dataCountStack = new Stack();
  1355.     JComboBox combobox = null;
  1356.     Vector parseBuffer = new Vector();    // Vector<ElementSpec>
  1357.     MutableAttributeSet charAttr = new SimpleAttributeSet();
  1358.     Stack charAttrStack = new Stack();
  1359.     Style resolver;
  1360.     Stack styleStack = new Stack();
  1361.     MutableAttributeSet attr = new SimpleAttributeSet();
  1362.     int inBlock = 0;
  1363.     SpecialCharTable specTable = new SpecialCharTable();
  1364.  
  1365.     class DataCounter {
  1366.     int dc = 0;
  1367.  
  1368.     public DataCounter() {
  1369.         ;
  1370.     }
  1371.  
  1372.     public void incCounter() {
  1373.         dc++;
  1374.     }
  1375.  
  1376.     public void decCounter() {
  1377.         dc--;
  1378.     }
  1379.  
  1380.     public boolean noPCData() {
  1381.         if (dc > 0)
  1382.         return false;
  1383.         else
  1384.         return true;
  1385.     }
  1386.     }
  1387. }
  1388.  
  1389. }
  1390.